package com.ubxtech.core.utils;

import cn.hutool.core.codec.Base64Decoder;
import cn.hutool.core.codec.Base64Encoder;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;

/**
 * aes加解密
 * AES/CBC/PKCS5Padding模式,需要向量值
 * @author Victor.Xiao
 * @since 2022-01-20 15:15
 * https://github.com/DarLiner/vjtools
 * https://github.com/xuzongbao/encryption
 * https://www.cnblogs.com/loong-hon/p/10145060.html
*/
public class AesUtil {


    private static final String AES_ALG = "AES";
    private static final String AES_CBC_ALG = "AES/CBC/PKCS5Padding";

    private static final int DEFAULT_AES_KEY_SIZE = 128;

    /**
     * 使用AES加密原始字符串.
     *
     * @param input 原始输入字符数组
     * @param key 符合AES要求的密钥
     */
    public static byte[] aesEncrypt(byte[] input, byte[] key) throws Exception  {
        return aes(input, key, Cipher.ENCRYPT_MODE);
    }

    /**
     * 使用AES加密原始字符串.
     * CBC,pkcs5padding,128位,带向量,base64编码输出,字符utf-8,秘钥长度必须是16,24,32
     * @param input 原始输入字符数组
     * @param key 符合AES要求的密钥
     * @param iv 初始向量
     */
    public static byte[] aesEncrypt(byte[] input, byte[] key, byte[] iv) throws Exception  {
        return aes(input, key, iv, Cipher.ENCRYPT_MODE);
    }

    /**
     * 使用AES解密字符串, 返回原始字符串.
     *
     * @param input Hex编码的加密字符串
     * @param key 符合AES要求的密钥
     */
    public static String aesDecrypt(byte[] input, byte[] key)  throws Exception {
        byte[] decryptResult = aes(input, key, Cipher.DECRYPT_MODE);
        return new String(decryptResult, StandardCharsets.UTF_8);
    }

    /**
     * 使用AES解密字符串, 返回原始字符串.
     * CBC,pkcs5padding,128位,带向量,base64编码输出,字符utf-8,秘钥长度必须是16,24,32
     * @param input Hex编码的加密字符串
     * @param key 符合AES要求的密钥
     * @param iv 初始向量
     */
    public static String aesDecrypt(byte[] input, byte[] key, byte[] iv) throws Exception  {
        byte[] decryptResult = aes(input, key, iv, Cipher.DECRYPT_MODE);
        return new String(decryptResult, StandardCharsets.UTF_8);
    }

    /**
     * 使用AES加密或解密无编码的原始字节数组, 返回无编码的字节数组结果.
     *
     * @param input 原始字节数组
     * @param key 符合AES要求的密钥
     * @param mode Cipher.ENCRYPT_MODE 或 Cipher.DECRYPT_MODE
     */
    private static byte[] aes(byte[] input, byte[] key, int mode) throws Exception  {
        //密钥生成器
        SecretKey secretKey = new SecretKeySpec(key, AES_ALG);
        //Cipher完成加解密
        Cipher cipher = Cipher.getInstance(AES_ALG);
        //初始化密码器，第一个参数为加密(Encrypt_mode)或者解密解密(Decrypt_mode)操作，第二个参数为使用的KEY
        cipher.init(mode, secretKey);
        //加解密
        return cipher.doFinal(input);

    }

    /**
     * 使用AES加密或解密无编码的原始字节数组, 返回无编码的字节数组结果.
     * CBC,pkcs5padding,128位,带向量,base64编码输出,字符utf-8,秘钥长度必须是16,24,32
     * @param input 原始字节数组
     * @param key 符合AES要求的密钥
     * @param iv 初始向量
     * @param mode Cipher.ENCRYPT_MODE 或 Cipher.DECRYPT_MODE
     */
    private static byte[] aes(byte[] input, byte[] key, byte[] iv, int mode) throws Exception {
            SecretKey secretKey = new SecretKeySpec(key, AES_ALG);
            IvParameterSpec ivSpec = new IvParameterSpec(iv);
            Cipher cipher = Cipher.getInstance(AES_CBC_ALG);
            cipher.init(mode, secretKey, ivSpec);
            return cipher.doFinal(input);
    }

    /**
     * 生成AES密钥,返回字节数组, 默认长度为128位(16字节).
     */
    public static byte[] generateAesKey() throws Exception  {
        return generateAesKey(DEFAULT_AES_KEY_SIZE);
    }

    /**
     * 生成AES密钥,可选长度为128,192,256位.
     */
    public static byte[] generateAesKey(int keysize) throws Exception  {

        KeyGenerator keyGenerator = KeyGenerator.getInstance(AES_ALG);
        keyGenerator.init(keysize);
        SecretKey secretKey = keyGenerator.generateKey();
        return secretKey.getEncoded();

    }
    
    /**
     * 加密
     * ECB模式,pkcs5padding,128位,base64编码输出,字符utf-8,秘钥长度必须是16,24,32
     * @author Victor.Xiao
     * @date 2020-04-30 18:53
     * @param data data
     * @param key key
     * @return java.lang.String
    */
    public static String encode(String data,String key){

        try {
            if(!isKeySizeValid(key.length())){
                throw new RuntimeException("秘钥长度不够");
            }

            return Base64Encoder.encode(AesUtil.aesEncrypt(data.getBytes(), key.getBytes()));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }


    /**
     * 解密
     * ECB模式,pkcs5padding,128位,base64编码输出,字符utf-8,秘钥长度必须是16,24,32
     * @author Victor.Xiao
     * @date 2020-04-30 18:53
     * @param data data
     * @param key key
     * @return java.lang.String
     */
    public static String decode(String data,String key){

        try {
            if(!isKeySizeValid(key.length())){
                throw new RuntimeException("秘钥长度不够");
            }
            return AesUtil.aesDecrypt(Base64Decoder.decode(data),key.getBytes());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }


    public static final int[] AES_KEY_SIZES = new int[]{16, 24, 32};
    static final boolean isKeySizeValid(int var0) {
        for(int var1 = 0; var1 < AES_KEY_SIZES.length; ++var1) {
            if (var0 == AES_KEY_SIZES[var1]) {
                return true;
            }
        }

        return false;
    }

    public static void main(String[] args) {
        try {
//            String aes = new BASE64Encoder().encode(AesUtil.aesEncrypt("Aimbot.01.b0416f03a8e4".getBytes(), ".01.b0416f03a8e4".getBytes()));
//            System.out.println(aes);
//
//            System.out.println(AesUtil.aesDecrypt(new BASE64Decoder().decodeBuffer(aes),".01.b0416f03a8e4".getBytes()));

            String aes = AesUtil.encode("Aimbot.01.b0416f03a8e4",".01.b0416f03a8e4");
            System.out.println(aes);
            System.out.println(AesUtil.decode(aes,".01.b0416f03a8e4"));

            //CBC,pkcs5padding,128位,带向量,base64编码输出,字符utf-8,秘钥长度必须是16,24,32
//            String aes = new BASE64Encoder().encode(AesUtil.aesEncrypt("Aimbot.01.b0416f03a8e4".getBytes(), "mima".getBytes(),".01.b0416f03a8e4".getBytes()));
//            System.out.println(aes);
//
//            System.out.println(AesUtil.aesDecrypt(new BASE64Decoder().decodeBuffer(aes),".01.b0416f03a8e4".getBytes(),".01.b0416f03a8e4".getBytes()));

            int[] ints = new int[]{0xe2, 0x11, 0xa8, 0x3d, 0x7b, 0xb4, 0x4a, 0xb9, 0x90, 0xcc, 0x44, 0x4a, 0xa0, 0xbd, 0xa5, 0xb2};
            byte[] bts = new byte[16];
            for (int i = 0; i < ints.length; i++) {
                bts[i] = (byte) ints[i];
            }
//            System.out.println(new String(bts,Charsets.UTF_8));
//            System.out.println(new String(bts,Charsets.ISO_8859_1));
//            System.out.println(new String(bts,Charsets.US_ASCII));

            String aes1 = Base64Encoder.encode(AesUtil.aesEncrypt("Aimbot.01.b0416f03a8e4".getBytes(), bts));
            System.out.println(aes1);
            System.out.println(AesUtil.aesDecrypt(Base64Decoder.decode(aes1),bts));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
